package at.irian.jsfatwork.broker.domain.account;

import at.irian.jsfatwork.broker.domain.BaseEntity;
import at.irian.jsfatwork.broker.domain.DomainModelException;
import at.irian.jsfatwork.broker.domain.client.Client;
import at.irian.jsfatwork.broker.domain.stock.Quote;
import at.irian.jsfatwork.broker.domain.stock.Stock;
import at.irian.jsfatwork.broker.domain.stock.StockExchange;
import org.hibernate.annotations.ForeignKey;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Thomas Spiegl
 */
@Entity
public class SecuritiesAccount extends ClientAccount {

    private List<SecuritiesAccountPosition> securitiesAccountPositions;

    private Long id;

    @OneToMany(cascade = CascadeType.ALL)
    @ForeignKey(name = "securities_account_id")
    public List<SecuritiesAccountPosition> getSecuritiesAccountPositions() {
        return securitiesAccountPositions;
    }

    public void setSecuritiesAccountPositions(List<SecuritiesAccountPosition> securitiesAccountPositions) {
        this.securitiesAccountPositions = securitiesAccountPositions;
    }

    @Transient
    public void validateCovered(Stock stock, Integer quantity) {
        SecuritiesAccountBalance balance = new SecuritiesAccountBalance(stock);
        for (SecuritiesAccountPosition position : securitiesAccountPositions) {
            position.accountBalance(balance);
        }
        if (!balance.isCovered(quantity)) {
            throw new DomainModelException(
                    "SecuritiesAccount " + getAccountNumber() +
                            " is not covered (Stock " + stock.getSymbol() + ", Quantity " + quantity + " > "  + balance.getBalance() + ")");
        }
    }

    public void credit(Stock stock, Integer quantity) {
        if (securitiesAccountPositions == null) {
            securitiesAccountPositions = new ArrayList<SecuritiesAccountPosition>();
        }
        SecuritiesAccountPosition position = new SecuritiesAccountPosition();
        position.setBookingDateTime(new Date());
        position.setQuantity(quantity);
        position.setStock(stock);
        securitiesAccountPositions.add(position);
    }

    public void debit(Stock stock, Integer quantity) {

        validateCovered(stock, quantity);

        if (securitiesAccountPositions == null) {
            securitiesAccountPositions = new ArrayList<SecuritiesAccountPosition>();
        }
        SecuritiesAccountPosition position = new SecuritiesAccountPosition();
        position.setBookingDateTime(new Date());
        position.setQuantity(-quantity);
        position.setStock(stock);
        securitiesAccountPositions.add(position);
    }

    @Transient
    public BigDecimal getSecuritiesAccountBalance(StockExchange stockExchange) {
        BigDecimal amount = BigDecimal.ZERO;
        for (SecuritiesAccountPosition position : securitiesAccountPositions) {
            amount = amount.add(position.getCurrentAmount(stockExchange));
        }
        return amount;
    }
}
